package de.ifi.lmu.snitzelhunt.util;

import java.util.ArrayList;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;

import de.ifi.lmu.snitzelhunt.basics.ActionTask;
import de.ifi.lmu.snitzelhunt.basics.ImageTask;
import de.ifi.lmu.snitzelhunt.basics.QuizTask;
import de.ifi.lmu.snitzelhunt.basics.Route;
import de.ifi.lmu.snitzelhunt.basics.Task;
import de.ifi.lmu.snitzelhunt.basics.User;
import de.ifi.lmu.snitzelhunt.util.basics.Ranking;
import de.ifi.lmu.snitzelhunt.util.basics.RankingContainer;
import de.ifi.lmu.snitzelhunt.util.basics.RouteInfoContainer;
import de.ifi.lmu.snitzelhunt.util.basics.TaskContainer;

/**
 * Helper Class for all JSON related methods using Google gson library
 * 
 * @author jaschkowitz
 * 
 */
public class GSonUtility {

	/**
	 * serializes a {@link Route} Object to a JSON string
	 * 
	 * @param route
	 * @return
	 */
	public static String serializeRoute(Route route) {
		Gson gson = createGSON();
		return gson.toJson(route);
	}

	/**
	 * deserializes a JSON string to a {@link Route} Object
	 * 
	 * @param json
	 * @return
	 */
	public static Route deserializeRoute(String json)
			throws JsonSyntaxException {
		Gson gson = createGSON();
		return gson.fromJson(json, Route.class);
	}

	/**
	 * serializes a {@link ArrayList<Task>} Object to a JSON string
	 * 
	 * @param tasks
	 * @return
	 */
	public static String serializeTaskList(ArrayList<Task> tasks) {
		TaskContainer tcont = new TaskContainer();
		tcont.setTasks(tasks);
		Gson gson = createGSON();
		return gson.toJson(tcont);
	}

	/**
	 * deserializes a JSON string to a {@link ArrayList<Task>} Object
	 * 
	 * @param json
	 * @return
	 */
	public static ArrayList<Task> deserializeTaskList(String json)
			throws JsonSyntaxException {
		Gson gson = createGSON();
		TaskContainer tcont = gson.fromJson(json, TaskContainer.class);
		return tcont.getTasks();
	}

	/**
	 * serializes a {@link ArrayList<User>} Object to a JSON string
	 * 
	 * @param users
	 * @return
	 */
	public static String serializeUserList(ArrayList<User> users) {
		Gson gson = new Gson();
		return gson.toJson(users, new TypeToken<ArrayList<User>>() {
		}.getType());
	}

	/**
	 * deserializes a JSON string to a {@link ArrayList<User>} Object
	 * 
	 * @param json
	 * @return
	 */
	public static ArrayList<User> deserializeUserList(String json)
			throws JsonSyntaxException {
		Gson gson = new Gson();
		ArrayList<User> users = gson.fromJson(json,
				new TypeToken<ArrayList<User>>() {
				}.getType());
		return users;
	}

	/**
	 * Returns a Gson Object that an handle the polymorphic type Task
	 * 
	 * @return
	 */
	public static Gson createGSON() {
		// for polymorphic type task
		RuntimeTypeAdapterFactory<Task> adapter = RuntimeTypeAdapterFactory
				.of(Task.class).registerSubtype(QuizTask.class)
				.registerSubtype(ActionTask.class).registerSubtype(ImageTask.class);

		return new GsonBuilder().registerTypeAdapterFactory(adapter).create();
	}

	/**
	 * serializes a {@link RouteInfoContainer} Object to a JSON string
	 * 
	 * @param route
	 * @return
	 */
	public static String serializeRouteInfoContainer(
			RouteInfoContainer loadRouteInfo) {
		Gson gson = createGSON();
		return gson.toJson(loadRouteInfo);
	}

	/**
	 * deserializes a JSON string to a {@link RouteInfoContainer} Object
	 * 
	 * @param json
	 * @return
	 */
	public static RouteInfoContainer deserializeRouteInfoContainer(String json)
			throws JsonSyntaxException {
		Gson gson = createGSON();
		return gson.fromJson(json, RouteInfoContainer.class);
	}

	/**
	 * serializes a {@link RankingContainer} Object to a JSON string
	 * 
	 * @param route
	 * @return
	 */
	public static String serializeRankingContainer(RankingContainer rankc) {
		Gson gson = createGSON();
		return gson.toJson(rankc);
	}

	/**
	 * deserializes a JSON string to a {@link RankingContainer} Object
	 * 
	 * @param json
	 * @return
	 */
	public static RankingContainer deserializeRankingContainer(String json)
			throws JsonSyntaxException {
		Gson gson = createGSON();
		return gson.fromJson(json, RankingContainer.class);
	}

	/**
	 * serializes a {@link Ranking} Object to a JSON string
	 * 
	 * @param route
	 * @return
	 */
	public static String serializeRanking(Ranking ranking) {
		Gson gson = createGSON();
		return gson.toJson(ranking);
	}

	/**
	 * deserializes a JSON string to a {@link Ranking} Object
	 * 
	 * @param json
	 * @return
	 */
	public static Ranking deserializeRanking(String json)
			throws JsonSyntaxException {
		Gson gson = createGSON();
		return gson.fromJson(json, Ranking.class);
	}

	/**
	 * serializes a long to a JSON string
	 * 
	 * @param route
	 * @return
	 */
	public static String serializeLong(long l) {
		Gson gson = new Gson();
		return gson.toJson(l);
	}

	/**
	 * deserializes a JSON string to a long
	 * 
	 * @param json
	 * @return
	 */
	public static long deserializeLong(String str) throws JsonSyntaxException {
		Gson gson = new Gson();
		return gson.fromJson(str, Long.class);
	}

}
